package com.example.devsa_platform.service.impl;

import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.aggregations.Buckets;
import co.elastic.clients.elasticsearch._types.aggregations.StringTermsBucket;
import com.example.devsa_platform.common.Result;
import com.example.devsa_platform.pojo.doc.UsageAndCommunityDoc;
import com.example.devsa_platform.pojo.vo.stats.UsageAndCommunityStatsVo;
import com.example.devsa_platform.service.UsageAndCommunityService;
import jakarta.annotation.Resource;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchAggregations;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.core.AggregationsContainer;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class UsageAndCommunityServiceImpl implements UsageAndCommunityService {

    @Resource
    private ElasticsearchTemplate template;

    @Override
    public Result<UsageAndCommunityStatsVo> UsageAndCommunityStats() {
        NativeQuery query = NativeQuery.builder()
                .withAggregation("stackOverflowSitesVisitedGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("stack_overflow_sites.keyword")))
                )
                .withAggregation("stackOverflowVisitFrequencyGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("so_visit_frequency.keyword")))
                )
                .withAggregation("stackOverflowAccountGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("so_account.keyword")))
                )
                .withAggregation("stackOverflowParticipationFrequencyGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("so_participation_frequency.keyword")))
                )
                .withAggregation("stackOverflowCommunityMemberGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("so_community_member.keyword")))
                )
                .build();

        AggregationsContainer<?> aggregationsContainer = template.search(query, UsageAndCommunityDoc.class).getAggregations();
        UsageAndCommunityStatsVo usageAndCommunityStatsVo = null;

        if (aggregationsContainer instanceof ElasticsearchAggregations elasticsearchAggregations) {
            List<Map<String, Object>> stackOverflowSitesVisitedGroup = parseAndAggregateResults("stackOverflowSitesVisitedGroup", elasticsearchAggregations);
            List<Map<String, Object>> stackOverflowVisitFrequencyGroup = parseAggregation("stackOverflowVisitFrequencyGroup", elasticsearchAggregations);
            List<Map<String, Object>> stackOverflowAccountGroup = parseAggregation("stackOverflowAccountGroup", elasticsearchAggregations);
            List<Map<String, Object>> stackOverflowParticipationFrequencyGroup = parseAggregation("stackOverflowParticipationFrequencyGroup", elasticsearchAggregations);
            List<Map<String, Object>> stackOverflowCommunityMemberGroup = parseAggregation("stackOverflowCommunityMemberGroup", elasticsearchAggregations);

            usageAndCommunityStatsVo = new UsageAndCommunityStatsVo(
                    stackOverflowSitesVisitedGroup,
                    stackOverflowVisitFrequencyGroup,
                    stackOverflowAccountGroup,
                    stackOverflowParticipationFrequencyGroup,
                    stackOverflowCommunityMemberGroup
            );
        }
        return Result.success(usageAndCommunityStatsVo);
    }

    private List<Map<String, Object>> parseAndAggregateResults(String aggregationName, ElasticsearchAggregations elasticsearchAggregations) {
        Map<String, Long> aggregatedCounts = new HashMap<>();

        List<Map<String, Object>> originalResults = parseAggregation(aggregationName, elasticsearchAggregations);
        for (Map<String, Object> result : originalResults) {
            String key = (String) result.get("key");
            Long docCount = ((Number) result.get("doc_count")).longValue();

            // Split the key by ";"
            String[] parts = key.split(";");
            for (String part : parts) {
                part = part.trim();
                aggregatedCounts.put(part, aggregatedCounts.getOrDefault(part, 0L) + docCount);
            }
        }

        // Convert aggregatedCounts to the desired output
        List<Map<String, Object>> parsedResults = new ArrayList<>();
        for (Map.Entry<String, Long> entry : aggregatedCounts.entrySet()) {
            Map<String, Object> map = new HashMap<>();
            map.put("key", entry.getKey());
            map.put("doc_count", entry.getValue());
            parsedResults.add(map);
        }

        return parsedResults;
    }

    private List<Map<String, Object>> parseAggregation(String aggName, ElasticsearchAggregations elasticsearchAggregations) {
        Buckets<StringTermsBucket> buckets = Objects.requireNonNull(elasticsearchAggregations.get(aggName)).aggregation().getAggregate().sterms().buckets();
        return buckets.array().stream()
                .map(bucket -> {
                    String key = bucket.key().stringValue();
                    long docCount = bucket.docCount();
                    Map<String, Object> map = new HashMap<>();
                    map.put("key", key);
                    map.put("doc_count", docCount);
                    return map;
                })
                .collect(Collectors.toList());
    }
}
